﻿@page "/diagram/flow-execution"

@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Diagrams
@using System.Collections.ObjectModel
@using DiagramShapes = Syncfusion.Blazor.Diagrams.Shapes
@using DiagramSegments = Syncfusion.Blazor.Diagrams.Segments

@inherits SampleBaseComponent;

<SampleDescription>
  <p> This sample demonstrates how we can process and get consecutive nodes and connectors.</p>  
  <p style="font-weight: bold;">A new blazor diagram component which provides better performance than the existing diagram control in Blazor WebAssembly App. It is available in preview mode. Check the samples <a target='_blank' href='diagramcomponent/flowchart'>here</a>.</p>
</SampleDescription>
<ActionDescription>
   <p>We can get the inward connections and outward connections of a node using the <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/methods/#get-the-edges'>GetEdges(nodeId,false)</a> and <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/methods/#get-the-edges'>GetEdges(nodeId,true)</a> methods of the diagram. By using the connector’s name collection, we can find the node using <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/methods/#get-the-node'>GetNode</a>. And also, we can get the nodes connected to the connector using the <a target='_blank' href='https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Diagrams.DiagramConnector.html#Syncfusion_Blazor_Diagrams_DiagramConnector_SourceID'>SourceID</a> and <a target='_blank' href='https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Diagrams.DiagramConnector.html#Syncfusion_Blazor_Diagrams_DiagramConnector_TargetID'>TargetID</a> properties of the connector.</p><br>
</ActionDescription>

@*Hidden:Lines*@
<link href="https://ej2.syncfusion.com/javascript/demos/src/diagram/styles/diagram-common.css" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
@*End:Hidden*@
<div class="col-lg-9 control-section" style="border-right: 1px solid #D7D7D7">
    <div id="diagram-space" class="content-wrapper">
        <SfDiagram Height="580px" @ref="@Diagram"
                    Nodes="@NodeCollection"
                    Connectors="@ConnectorCollection">
            <DiagramSnapSettings Constraints="@SnapConstraints.None"></DiagramSnapSettings>
            <DiagramEvents Created="@OnCreated" SelectionChanged="@OnSelectionChanged"></DiagramEvents>
        </SfDiagram>
    </div>
</div>
@*Hidden:Lines*@
<div class="col-lg-3 property-section">
    <style>
        .row {
            margin-left: 0px;
            margin-right: 0px;
            display: block;
        }

        .col-xs-7 {
            width: 300px;
            padding-left: 0px;
            padding-right: 0px;
        }
    </style>
    <div class="property-panel-header">
        Choose a flow
    </div>

    <div class="row property-panel-content">
        <div class="row" style="padding-top: 8px">
            <div class="col-xs-7">
                <SfRadioButton Label="None" Name="radio" Value="UnhighlightAll" @bind-Checked="stringChecked" ValueChange="OnCheckedItemChange" TChecked="string"></SfRadioButton>
            </div>
        </div>
        <div class="row" style="padding-top: 8px">
            <div class="col-xs-7">
                <SfRadioButton Label="Incoming connections" Name="radio" @bind-Checked="stringChecked"  Value="LinksInto" ValueChange="OnCheckedItemChange" TChecked="string"></SfRadioButton>
            </div>
        </div>
        <div class="row" style="padding-top: 8px">
            <div class="col-xs-7">
                <SfRadioButton Label="Outgoing connections" Name="radio" @bind-Checked="stringChecked"  Value="LinksOutOf" ValueChange="OnCheckedItemChange" TChecked="string"></SfRadioButton>
            </div>
        </div>
        <div class="row" style="padding-top: 8px">
            <div class="col-xs-7">
                <SfRadioButton Label="Incoming and outgoing connections" @bind-Checked="stringChecked"  Name="radio" Value="LinksConnected" ValueChange="OnCheckedItemChange" TChecked="string"></SfRadioButton>
            </div>
        </div>
        <div class="row" style="padding-top: 8px">
            <div class="col-xs-7">
                <SfRadioButton Label="Incoming nodes" Name="radio" @bind-Checked="stringChecked"  Value="NodesInto" ValueChange="OnCheckedItemChange" TChecked="string"></SfRadioButton>
            </div>
        </div>
        <div class="row" style="padding-top: 8px">
            <div class="col-xs-7">
                <SfRadioButton Label="Outgoing nodes" Name="radio" @bind-Checked="stringChecked"  Value="NodesOutOf" ValueChange="OnCheckedItemChange" TChecked="string"></SfRadioButton>
            </div>
        </div>
        <div class="row" style="padding-top: 8px">
            <div class="col-xs-7">
                <SfRadioButton Label="Incoming and outgoing nodes" @bind-Checked="stringChecked"  Name="radio" Value="NodesConnected" ValueChange="OnCheckedItemChange" TChecked="string"></SfRadioButton>
            </div>
        </div>
        <div class="row" style="padding-top: 8px">
            <div class="col-xs-7">
                <SfRadioButton Label="Flow of execution" Name="radio"  @bind-Checked="stringChecked"  Value="NodesReachable" ValueChange="OnCheckedItemChange" TChecked="string"></SfRadioButton>
            </div>
        </div>
    </div>
</div>
@*End:Hidden*@


@code
{
    int connectorCount;
    string currentButton;
    private string stringChecked = "UnhighlightAll";
    List<DiagramConnector> highLightedConnector = new List<DiagramConnector>();
    List<DiagramNode> highLightedNode = new List<DiagramNode>();
    List<DiagramConnector> reachableConnectors = new List<DiagramConnector>();

    // Reference to diagram
    SfDiagram Diagram;

    // Defines diagram's nodes collection
    public ObservableCollection<DiagramNode> NodeCollection { get; set; }

    // Defines diagram's connector collection
    public ObservableCollection<DiagramConnector> ConnectorCollection { get; set; }

    /// <summary>
    /// Initializing the objects
    /// </summary>
    protected override void OnInitialized()
    {
        InitDiagramModel();
    }
    private async void OnSelectionChanged(IBlazorSelectionChangeEventArgs args)
    {
        if (args.State == EventState.Changed)
            await ApplyChanges(currentButton);
    }
    private void InitDiagramModel()
    {
        NodeCollection = new ObservableCollection<DiagramNode>();
        ConnectorCollection = new ObservableCollection<DiagramConnector>();

        CreateNode("node1", 100, 125, FlowShapes.Terminator, "Begin");
        CreateNode("node2", 300, 125, FlowShapes.Process, "Specify collection");
        CreateNode("node3", 500, 125, FlowShapes.Decision, "Particulars \n required?");
        CreateNode("node4", 730, 125, FlowShapes.Process, "Specify particulars");
        CreateNode("node5", 500, 225, FlowShapes.Process, "Design collection");
        CreateNode("node6", 500, 320, FlowShapes.Process, "Cluster of events");
        CreateNode("node7", 500, 420, FlowShapes.Process, "Start the process");
        CreateNode("node8", 730, 320, FlowShapes.Process, "Record and analyze \n results");
        CreateNode("node9", 730, 420, FlowShapes.Terminator, "End");

        Syncfusion.Blazor.Diagrams.DiagramConnectorSegment segment1 = new Syncfusion.Blazor.Diagrams.DiagramConnectorSegment()
        {
            Type = DiagramSegments.Orthogonal,
            Length = 75,
            Direction = Direction.Bottom
        };

        CreateConnector("node1", "node2");
        CreateConnector("node2", "node3");
        CreateConnector("node3", "node4", "Yes");
        CreateConnector("node3", "node5", "No");
        CreateConnector("node5", "node6");
        CreateConnector("node6", "node7");
        CreateConnector("node8", "node6");
        CreateConnector("node7", "node9");
        CreateConnector("node4", "node5", default(string), segment1);
    }

    private void CreateNode(string id, double x, double y, FlowShapes shape, string label)
    {
        DiagramNodeAnnotation annotation = new DiagramNodeAnnotation() { Content = label };

        DiagramNode diagramNode = new DiagramNode()
        {
            Id = id,
            OffsetX = x,
            OffsetY = y,
            Width = 150,
            Height = 50,
            Shape = new DiagramShape() { Type = DiagramShapes.Flow, FlowShape = shape },
            Annotations = new ObservableCollection<DiagramNodeAnnotation>() { annotation },
            Style = new NodeShapeStyle() { Fill = "#FBF6E1", StrokeColor = "#E8DFB6", StrokeWidth = 2 }
        };

        NodeCollection.Add(diagramNode);
    }

    private void CreateConnector(string sourceId, string targetId, string label = default(string), Syncfusion.Blazor.Diagrams.DiagramConnectorSegment segment = null)
    {
        DiagramConnector diagramConnector = new DiagramConnector()
        {
            Id = string.Format("connector{0}", ++connectorCount),
            SourceID = sourceId,
            TargetID = targetId,
            Style = new ConnectorShapeStyle() { StrokeWidth = 2, StrokeColor = "#8D8D8D" },
            TargetDecorator = new ConnectorTargetDecorator()
            {
                Style = new DecoratorShapeStyle() { StrokeColor = "#8D8D8D", Fill = "#8D8D8D" }
            }
        };

        if (label != default(string))
        {
            var annotation = new DiagramConnectorAnnotation()
            {
                Content = label,
                Style = new AnnotationStyle()
                {
                    Fill = "white"
                }
            };
            diagramConnector.Annotations = new ObservableCollection<DiagramConnectorAnnotation>() { annotation };
        }

        if (segment != null)
        {
            diagramConnector.Type = DiagramSegments.Orthogonal;
            diagramConnector.Segments = new ObservableCollection<Syncfusion.Blazor.Diagrams.DiagramConnectorSegment>() { segment };
        }

        ConnectorCollection.Add(diagramConnector);
    }

    private async void OnCheckedItemChange(Syncfusion.Blazor.Buttons.ChangeArgs<string> args)
    {
        currentButton = args.Value.ToString();
        await ApplyChanges(currentButton);
    }

    public async Task ApplyChanges(string selectedButton)
    {
        UnHighLight();
        switch (selectedButton)
        {
            case "LinksInto":
                await LinkedConnector(false);
                break;
            case "LinksOutOf":
                await LinkedConnector(true);
                break;
            case "LinksConnected":
                await LinkedConnector(false);
                await LinkedConnector(true);
                break;
            case "NodesInto":
                await LinkedNode(false);
                break;
            case "NodesOutOf":
                await LinkedNode(true);
                break;
            case "NodesConnected":
                await  LinkedNode(false);
                await  LinkedNode(true);
                break;
            case "NodesReachable":
                await ChildrenFlow();
                break;
        }
    }

    public async Task LinkedConnector(bool isOutEdge)
    {
        if (Diagram.SelectedItems.Nodes.Count > 0)
        {
            string nodeId = this.Diagram.SelectedItems.Nodes[0].Id;
            string[] edges = await Diagram.GetEdges(nodeId, isOutEdge);
            foreach (string edge in edges)
            {
                DiagramConnector connector = Diagram.GetConnector(edge);
                highLightedConnector.Add(connector);
                connector.Style.StrokeColor = "#1413F8";
                connector.TargetDecorator.Style.StrokeColor = "#1413F8";
                connector.TargetDecorator.Style.Fill = "#1413F8";
            }
        }
    }

    public async Task LinkedNode(bool isOutEdge)
    {
        if (Diagram.SelectedItems.Nodes.Count > 0)
        {
            string nodeId = this.Diagram.SelectedItems.Nodes[0].Id;
            string[] edges = await Diagram.GetEdges(nodeId, isOutEdge);
            foreach (string edge in edges)
            {
                DiagramConnector connector = Diagram.GetConnector(edge);
                DiagramNode node = null;
                if (isOutEdge)
                {
                    node = Diagram.GetNode(connector.TargetID);
                }
                else
                {
                    node = Diagram.GetNode(connector.SourceID);
                }

                highLightedNode.Add(node);
                node.Style.StrokeColor = "#1413F8";
            }
        }
    }

    public async Task ChildrenFlow()
    {
        if (Diagram.SelectedItems.Nodes.Count > 0)
        {
            string nodeId = this.Diagram.SelectedItems.Nodes[0].Id;
            await FindReachable(nodeId);
            if (reachableConnectors.Count > 0)
            {
                foreach (DiagramConnector connector in reachableConnectors)
                {
                    highLightedConnector.Add(connector);
                    connector.Style.StrokeColor = "#1413F8";
                    connector.TargetDecorator.Style.StrokeColor = "#1413F8";
                    connector.TargetDecorator.Style.Fill = "#1413F8";
                }

                reachableConnectors.Clear();
            }
        }
    }

    public async Task<List<DiagramConnector>> FindReachable(string nodeId)
    {
        string[] edges = await Diagram.GetEdges(nodeId, true);
        foreach (string edge in edges)
        {
            DiagramConnector connector = Diagram.GetConnector(edge);
            if (reachableConnectors.Contains(connector))
            {
                continue;
            }

            if (connector.Annotations == null || connector.Annotations.Count == 0 || connector.Annotations[0].Content != "No")
            {
                reachableConnectors.Add(connector);
                await FindReachable(connector.TargetID);
            }
        }
        return reachableConnectors;
    }

    public void UnHighLight()
    {
        foreach (DiagramNode node in highLightedNode)
        {
            node.Style.StrokeColor = "#E8DFB6";
        }

        foreach (DiagramConnector connector in highLightedConnector)
        {
            connector.Style.StrokeColor = "#8D8D8D";
            connector.TargetDecorator.Style.StrokeColor = "#8D8D8D";
            connector.TargetDecorator.Style.Fill = "#8D8D8D";
        }

        highLightedNode.Clear();
        highLightedConnector.Clear();
    }
    private async void OnCreated(object obj)
    {
        await Diagram.Select(new ObservableCollection<DiagramNode>() { Diagram.Nodes[2] }, null);
    }    
}
